package com.zhenmaitang.clinic_sys.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhenmaitang.clinic_sys.util.ApiResponse;
import com.zhenmaitang.clinic_sys.service.UriPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class PermissionInterceptor implements HandlerInterceptor {
    
    @Autowired
    private PermissionEvaluator permissionEvaluator;
    
    @Autowired
    private UriPermissionService uriPermissionService;
    
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 只处理方法处理器
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        // 获取当前用户ID
        Integer userId = getCurrentUserId();
        if (userId == null) {
            handlePermissionDenied(response);
            return false;
        }
        
        // 1. 首先尝试基于URI的权限判断
        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        
        // 如果URI权限判断通过，则允许访问
        if (uriPermissionService.hasUriPermission(userId, requestUri, method)) {
            return true;
        }
        
        // 2. 如果URI权限判断未通过，再尝试基于注解的权限判断
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // 检查方法上的权限注解
        HasPermission methodPermission = handlerMethod.getMethodAnnotation(HasPermission.class);
        if (methodPermission != null) {
            if (!checkPermission(methodPermission)) {
                handlePermissionDenied(response);
                return false;
            }
            return true;
        }
        
        // 检查类上的权限注解
        HasPermission classPermission = handlerMethod.getBeanType().getAnnotation(HasPermission.class);
        if (classPermission != null) {
            if (!checkPermission(classPermission)) {
                handlePermissionDenied(response);
                return false;
            }
            return true;
        }
        
        // 如果既没有URI权限也没有注解权限，则默认拒绝访问
        handlePermissionDenied(response);
        return false;
    }
    
    /**
     * 获取当前登录用户ID
     */
    private Integer getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        
        Object principal = authentication.getPrincipal();
        if (principal instanceof CustomUserDetails) {
            return ((CustomUserDetails) principal).getUserId();
        }
        
        return null;
    }
    
    /**
     * 检查权限注解
     * @param permission 权限注解
     * @return 是否有权限
     */
    private boolean checkPermission(HasPermission permission) {
        // 如果指定了权限代码，则检查权限代码
        if (!permission.value().isEmpty()) {
            return permissionEvaluator.hasPermissionCode(permission.value());
        }
        
        // 如果指定了资源和操作，则检查资源操作权限
        if (!permission.resource().isEmpty() && !permission.action().isEmpty()) {
            return permissionEvaluator.hasResourcePermission(permission.resource(), permission.action());
        }
        
        return false;
    }
    
    /**
     * 处理权限不足的情况，封装response
     * @param response 响应对象
     * @throws IOException 处理响应时可能抛出的异常
     */
    private void handlePermissionDenied(HttpServletResponse response) throws IOException {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType("application/json;charset=UTF-8");
        
        ApiResponse<String> apiResponse = ApiResponse.error("权限不足，无法访问此资源");
        String jsonResponse = objectMapper.writeValueAsString(apiResponse);
        
        response.getWriter().write(jsonResponse);
    }
}